package com.icw.decoupling.impl.tool;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.icw.configuration.ConstSettings;
import com.icw.decoupling.defi.proxy.RestfulMgrProxy;
import com.icw.decoupling.defi.tool.ResourceContextProcessor;
import com.icw.utility.BeanCtxUtils;
import com.icw.utility.IcwUtils;
import com.icw.utility.PoEntityHelper;

@Component
public class DefaultResourceContextProcessor implements ResourceContextProcessor {

	@Override
	public void process(Object[] actions, Map<String, Object> context) throws Exception {
		RestfulMgrProxy mgr = BeanCtxUtils.getBeanByType(RestfulMgrProxy.class);
		for (int i = 0; i < actions.length; i++) {
			final Object temp = actions[i];
			PoEntityHelper.parseExpression(context, temp);
			final Object kobj = PoEntityHelper.readValueByProperty(temp, "k");
			if (!String.class.isInstance(kobj)) continue;
			final String k = String.class.cast(kobj);
			if (StringUtils.equals("!", k.substring(0, 1))) {
				// skip
			} else {
				Object v = PoEntityHelper.readValueByProperty(temp, "v");
				if (PoEntityHelper.isBasicType(v) || Collection.class.isInstance(v) || v.getClass().isArray()) {
					//
				} else if (RSRC_VAL_KEYSET.stream().allMatch(key -> PoEntityHelper.containsKeyByProperty(v, key))) {
					String rsrcNm = (String) PoEntityHelper.readValueByProperty(v, "resourceName");
					String action = (String) PoEntityHelper.readValueByProperty(v, "action");
					@SuppressWarnings("unchecked")
					Map<String, Object> params = (Map<String, Object>) PoEntityHelper.readValueByProperty(v, "params");
					String target = (String) PoEntityHelper.readValueByProperty(v, "target");
					Map<String, Object> data = IcwUtils.mapObject();
					if ("getone".equals(action)) {
						mgr.getone(ConstSettings.LRsrcEntityMap.get(rsrcNm), params, null, null, data);
					}
					if ("getlist".equals(action)) {
						mgr.getlist(ConstSettings.LRsrcEntityMap.get(rsrcNm), params, null, null, data);
					}
					if ("post".equals(action)) {
						mgr.post(ConstSettings.LRsrcEntityMap.get(rsrcNm), params, null, null, data);
					}
					if ("patch".equals(action)) {
						mgr.patch(ConstSettings.LRsrcEntityMap.get(rsrcNm), params, null, null, data);
					}
					writeValue(temp, data, target);
				} else if (PoEntityHelper.containsKeyByProperty(v, "methodName")) {
					Object data = findMethod(v).invoke(findBean(v), findArgs(v));
					String target = (String) PoEntityHelper.readValueByProperty(v, "target");
					writeValue(temp, data, target);
				}
				PoEntityHelper.writeValueByProperty(context, (String) k, PoEntityHelper.readValueByProperty(temp, "v"));
			}
		}
	}

	private void writeValue(Object temp, Object data, String target) throws Exception {
		Object value = readValueByTarget(data, target);
		PoEntityHelper.writeValueByProperty(temp, "v", value);
	}

	private Object readValueByTarget(Object data, String target) throws Exception {
		if (target == null || "".equals(target)) {
			return data;
		} else if (target.indexOf("=") >= 0) {
			return PoEntityHelper.transFormStructure(data, target);
		} else {
			return PoEntityHelper.readValueByProperty(data, target);
		}
	}

	private Object[] findArgs(Object v) {
		Object[] __args = IcwUtils.ifNull(PoEntityHelper.toObjectArray(PoEntityHelper.readValueByProperty(v, "args")), () -> new Object[] {});
		return __args;
	}

	private Object findBean(Object v) throws Exception {
		String methodFullName = (String) PoEntityHelper.readValueByProperty(v, "methodName");
		int lastIndex = methodFullName.lastIndexOf(".");
		Class<?> beanClass = Class.forName(methodFullName.substring(0, lastIndex));
		Object bean = BeanCtxUtils.getBeanByType(beanClass);
		return bean;
	}

	private Method findMethod(Object v) throws Exception {
		String methodFullName = (String) PoEntityHelper.readValueByProperty(v, "methodName");
		int lastIndex = methodFullName.lastIndexOf(".");
		Class<?> beanClass = Class.forName(methodFullName.substring(0, lastIndex));
		String methodName = methodFullName.substring(lastIndex + 1);
		Method method = Stream.of(beanClass.getMethods()).filter(m -> m.getName().equals(methodName)).findFirst().get();
		return method;
	}

	@Override
	public void process(Object[] actions) throws Exception {
		process(actions, IcwUtils.mapObject());
	}

	private final static Set<String> RSRC_VAL_KEYSET = SetUtils.unmodifiableSet("resourceName", "action", "params", "target");
}
